﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;

namespace OpenPhotoAlbum.BusinessLogics
{
    public class CacheManager
    {
        #region Singleton

        private CacheManager() { }

        private static readonly CacheManager _instance = new CacheManager();

		public static CacheManager Instance
		{
			get { return _instance; }
		}

        static CacheManager() { }

        #endregion

        private static Dictionary<Guid, CacheItem> cache = new Dictionary<Guid, CacheItem>();

        private const int CacheDuration = 1200; // in seconds

        public void WriteCache<T>(Guid key, T value)
        {
            lock (cache)
            {
				try { cache.Add(key, new CacheItem(value, DateTime.UtcNow.AddSeconds(CacheDuration))); }
				catch (ArgumentException excpt) { Debug.WriteLine(excpt.Message); }
                Debug.WriteLine(key, "WriteCache");
            }
        }

        public bool ContainsKey(Guid key)
        {
            lock (cache) { return cache.ContainsKey(key); }
        }

        public T ReadCache<T>(Guid key)
        {
            lock (cache)
            {
                T result = (T)cache[key].Value;
                Debug.WriteLine(key, "ReadCache");
                return result;
            }
        }

        public void RemoveCache(Guid key)
        {
            lock (cache)
            {
                cache.Remove(key);
                Debug.WriteLine(key, "RemoveCache");
            }
        }


		private static DateTime lastRecycling = DateTime.UtcNow;
		private const int RecyclingInterval = 120;

        public void RecycleIfNecessary()
        {
            DateTime now = DateTime.UtcNow;

            lock (cache)
            {
				if (now.Subtract(lastRecycling).TotalSeconds < RecyclingInterval) { return; }
				
				lastRecycling = now;

                List<Guid> deleting = new List<Guid>();

                foreach (KeyValuePair<Guid, CacheItem> pair in cache)
                {
                    if (now.CompareTo(pair.Value.ExpireDate) > 0)
                    {
                        deleting.Add(pair.Key);
                    }
                }
                foreach (Guid id in deleting)
                {
                    RemoveCache(id);
                }
            }
        }

        public int Count
        {
            get { lock (cache) { return cache.Count; } }
        }

		public void ClearCache()
		{
			lock (cache) { cache.Clear(); }
		}
    }

    class CacheItem
    {
        public CacheItem(object value, DateTime expireDate)
        {
            Value = value;
            ExpireDate = expireDate;
        }

        public object Value { get; set; }
        public DateTime ExpireDate { get; set; }
    }
}
